package com.easyjob.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.easyjob.entity.dto.AppUserLoginDto;
import com.easyjob.entity.dto.ExamConfigDto;
import com.easyjob.entity.enums.*;
import com.easyjob.entity.po.*;
import com.easyjob.entity.query.*;
import com.easyjob.entity.vo.*;
import com.easyjob.entity.vo.app.ExamQuestionVO;
import com.easyjob.exception.BusinessException;
import com.easyjob.mappers.*;
import com.easyjob.mappers.plus.AppExamCountMapper;
import com.easyjob.mappers.plus.AppExamQuestionPlusMapper;
import com.easyjob.mappers.plus.QuestionItemPlusMapper;
import com.easyjob.mappers.plus.QuestionPlusMapper;
import com.easyjob.service.AppExamService;
import com.easyjob.service.QuestionInfoService;
import com.easyjob.utils.BeanCopyUtils;
import com.easyjob.utils.StringTools;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 用户在线考试 业务接口实现
 */
@Service("appExamService")
public class AppExamServiceImpl implements AppExamService {

    @Resource
    private AppExamMapper<AppExam, AppExamQuery> appExamMapper;

    @Resource
    private AppExamQuestionPlusMapper appExamQuestionPlusMapper;

    @Resource
    private QuestionPlusMapper questionPlusMapper;

    @Resource
    private QuestionItemPlusMapper questionItemPlusMapper;

    @Resource
    private QuestionInfoServiceImpl questionInfoServiceImpl;

    @Resource
    private AppExamCountMapper appExamCountMapper;

    @Resource
    private AppExamQuestionMapper<AppExamQuestion, AppExamQuestionQuery> appExamQuestionMapper;


    @Resource
    private ExamQuestionMapper<ExamQuestion, ExamQuestionQuery> examQuestionMapper;

    @Resource
    private ExamQuestionItemMapper<ExamQuestionItem, ExamQuestionItemQuery> examQuestionItemMapper;

    @Resource
    private AppUserCollectMapper<AppUserCollect, AppUserCollectQuery> appUserCollectMapper;

    @Resource
    private QuestionInfoService questionInfoService;

    /**
     * 根据条件查询列表
     */
    @Override
    public List<AppExam> findListByParam(AppExamQuery param) {
        return this.appExamMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(AppExamQuery param) {
        return this.appExamMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<AppExam> findListByPage(AppExamQuery param) {
        int count = this.findCountByParam(param);
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<AppExam> list = this.findListByParam(param);
        PaginationResultVO<AppExam> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(AppExam bean) {
        return this.appExamMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<AppExam> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.appExamMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<AppExam> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.appExamMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(AppExam bean, AppExamQuery param) {
        StringTools.checkParam(param);
        return this.appExamMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(AppExamQuery param) {
        StringTools.checkParam(param);
        return this.appExamMapper.deleteByParam(param);
    }

    /**
     * 根据ExamId获取对象
     */
    @Override
    public AppExam getAppExamByExamId(Integer examId) {
        return this.appExamMapper.selectByExamId(examId);
    }

    /**
     * 根据ExamId修改
     */
    @Override
    public Integer updateAppExamByExamId(AppExam bean, Integer examId) {
        return this.appExamMapper.updateByExamId(bean, examId);
    }

    /**
     * 根据ExamId删除
     */
    @Override
    public Integer deleteAppExamByExamId(Integer examId) {
        return this.appExamMapper.deleteByExamId(examId);
    }

    @Override
    public JSONObject createExam(ExamConfigDto configDto, AppUserLoginDto appUserLoginDto) {
        if (configDto.getExamModel() == 0) return handleModelOne(configDto, appUserLoginDto);
        else if (configDto.getExamModel() == 1) return handleModelTwo(configDto, appUserLoginDto);
        return handleModelThree(configDto, appUserLoginDto);
    }

    @Transactional(rollbackFor = Exception.class)
    public JSONObject handleModelThree(ExamConfigDto configDto, AppUserLoginDto appDto) {
        AppExam appExam = insertExamRecord(configDto, appDto);
        List<QuestionInfoVo> questionInfoVoList = questionInfoService.getQuestionInfoByConfig(configDto, appDto);
        return parse(questionInfoVoList, appExam, appDto);
    }

    @Transactional(rollbackFor = Exception.class)
    JSONObject handleModelTwo(ExamConfigDto configDto, AppUserLoginDto appDto) {
        AppExam appExam = insertExamRecord(configDto, appDto);
        List<QuestionInfoVo> questionInfoVoList = questionInfoService.getQuestionInfoByConfig(configDto, appDto);
        return parse(questionInfoVoList, appExam, appDto);
    }

    @Transactional(rollbackFor = Exception.class)
    JSONObject parse(List<QuestionInfoVo> questionInfoVoList, AppExam appExam, AppUserLoginDto appDto) {
        JSONObject data = new JSONObject();
        List<AppExamQuestion> appExamQuestionList = new ArrayList<>();
        for (QuestionInfoVo examQuestion : questionInfoVoList) {
            AppExamQuestion appExamQuestion = new AppExamQuestion();
            appExamQuestion.setExamId(appExam.getExamId());
            appExamQuestion.setQuestionId(examQuestion.getQuestionId());
            appExamQuestion.setUserId(appDto.getUserId());
            appExamQuestion.setAnswerResult(AnswerResultEnum.INIT.getResult());
            appExamQuestionList.add(appExamQuestion);
        }
        if (!appExamQuestionList.isEmpty()) {
            appExamQuestionMapper.insertBatch(appExamQuestionList);
        }
        data.put("examInfo", appExam);
        data.put("examQuestionList", questionInfoVoList);
        return data;
    }

    @Transactional(rollbackFor = Exception.class)
    JSONObject handleModelOne(ExamConfigDto configDto, AppUserLoginDto appDto) {
        AppExam appExam = insertExamRecord(configDto, appDto);
        List<QuestionInfoVo> questionInfoVoList = questionInfoService.getInfoByChapterId(configDto.getId(), configDto.getRadio1());
        return parse(questionInfoVoList, appExam, appDto);
    }

    private AppExam insertExamRecord(ExamConfigDto configDto, AppUserLoginDto appDto) {
        LocalDateTime startTime = LocalDateTime.now();
        Date date1 = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
        AppExam appExam = new AppExam();
        appExam.setCounter(configDto.getRadio3() * 60.0);
        appExam.setUserId(appDto.getUserId());
        appExam.setNickName(appDto.getNickName());
        appExam.setCreateTime(date1);
        appExam.setStatus(AppExamStatusEnum.INIT.getStatus());
        appExamMapper.insert(appExam);
        return appExam;
    }

    @Override
    public JSONObject loadHistoryById(Integer examId, AppUserLoginDto appDto) {
        List<AppExamQuestion> appExamQuestionList = appExamQuestionPlusMapper.selectList(new LambdaQueryWrapper<AppExamQuestion>().eq(AppExamQuestion::getExamId, examId));
        Map<Integer, String> stringMap = appExamQuestionList.
                stream()
                .collect(Collectors.toMap(AppExamQuestion::getQuestionId, item -> {
                    if (item.getUserAnswer() == null) {
                        return "";
                    }
                    return item.getUserAnswer();
                }, (o1, o2) -> o2));
        List<Integer> ids = appExamQuestionList.stream().map(AppExamQuestion::getQuestionId).collect(Collectors.toList());
        Map<Integer, List<QuestionInfoVo>> listMap = questionPlusMapper.selectList(new LambdaQueryWrapper<ExamQuestion>().in(ExamQuestion::getQuestionId, ids).orderByDesc(ExamQuestion::getSort)).
                stream().
                map(item -> {
                    QuestionInfoVo questionInfoVo = BeanCopyUtils.copyBean(item, QuestionInfoVo.class);
                    List<ExamQuestionItem> questionItemList = questionItemPlusMapper.selectList(new QueryWrapper<ExamQuestionItem>().eq("question_id", item.getQuestionId()));
                    questionInfoVo.setQuestionItemList(questionItemList);
                    questionInfoVo.setUserAnswer(stringMap.get(item.getQuestionId()));
                    return questionInfoVo;
                }).collect(Collectors.groupingBy(QuestionInfoVo::getQuestionType));
        if (listMap.isEmpty()) {
            throw new BusinessException("该次考试无效，原因为：无考题！");
        }
        List<QuestionInfoVo> questionInfoVoList = questionInfoServiceImpl.convertQuestion2Vo(listMap, 0, null);
        AppExam appExam = new AppExam();
        appExam.setUserId(appDto.getUserId());
        appExam.setNickName(appDto.getNickName());
        appExam.setStatus(AppExamStatusEnum.FINISHED.getStatus());
        appExam.setExamId(examId);
        JSONObject data = new JSONObject();
        data.put("examInfo", appExam);
        data.put("examQuestionList", questionInfoVoList);
        return data;
    }

    @Override
    public AppExam createExam(String categoryIds, AppUserLoginDto appDto) {
        AppExamQuestionQuery appExamQuestionQuery = new AppExamQuestionQuery();
        appExamQuestionQuery.setUserId(appDto.getUserId());
        appExamQuestionQuery.setAnswerResult(AnswerResultEnum.RIGHT.getResult());
        List<AppExamQuestion> dbAppExamQuestionList = appExamQuestionMapper.selectList(appExamQuestionQuery);
        List<Integer> excludeQuestionIdList = dbAppExamQuestionList.stream().map(item -> item.getQuestionId()).collect(Collectors.toList());

        ExamQuestionQuery examQuestionQuery = new ExamQuestionQuery();
        examQuestionQuery.setCategoryIds(categoryIds.split(","));
        examQuestionQuery.setExcludeQuestinIdList(excludeQuestionIdList);
        examQuestionQuery.setOrderBy("rand()");
        examQuestionQuery.setStatus(PostStatusEnum.POST.getStatus());
        examQuestionQuery.setPageNo(1);
        examQuestionQuery.setSimplePage(new SimplePage(0, PageSize.SIZE50.getSize()));
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(examQuestionQuery);
        if (examQuestionList.isEmpty()) {
            throw new BusinessException("该分类木有新题了");
        }
        AppExam appExam = new AppExam();
        appExam.setUserId(appDto.getUserId());
        appExam.setNickName(appDto.getNickName());
        appExam.setCreateTime(new Date());
        appExam.setStatus(AppExamStatusEnum.INIT.getStatus());
        appExamMapper.insert(appExam);

        List<AppExamQuestion> appExamQuestionList = new ArrayList<>();
        for (ExamQuestion examQuestion : examQuestionList) {
            AppExamQuestion appExamQuestion = new AppExamQuestion();
            appExamQuestion.setExamId(appExam.getExamId());
            appExamQuestion.setQuestionId(examQuestion.getQuestionId());
            appExamQuestion.setUserId(appDto.getUserId());
            appExamQuestion.setAnswerResult(AnswerResultEnum.INIT.getResult());
            appExamQuestionList.add(appExamQuestion);
        }
        if (!appExamQuestionList.isEmpty()) {
            appExamQuestionMapper.insertBatch(appExamQuestionList);
        }
        return appExam;
    }

    @Override
    public List<ExamQuestionVO> getAppExamQuestion(AppExamQuestionQuery appExamQuestionQuery) {
        //查询考卷的考题
        List<AppExamQuestion> appExamQuestionList = appExamQuestionMapper.selectList(appExamQuestionQuery);

        //考题map
        Map<Integer, AppExamQuestion> appExamQuestionMap = new HashMap<>();
        if (appExamQuestionQuery.getShowUserAnswer() != null && appExamQuestionQuery.getShowUserAnswer()) {
            appExamQuestionMap = appExamQuestionList.stream().collect(Collectors.toMap(item -> item.getQuestionId(),
                    Function.identity(), (data1, data2) -> data2));
        }
        //考题问题ID
        List<String> questionIdList = appExamQuestionList.stream().map(item -> item.getQuestionId() + "").collect(Collectors.toList());

        //查询考题
        ExamQuestionQuery examQuestionQuery = new ExamQuestionQuery();
        examQuestionQuery.setQueryAnswer(appExamQuestionQuery.getShowUserAnswer());
        examQuestionQuery.setQuestionIds(questionIdList.toArray(new String[appExamQuestionList.size()]));
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(examQuestionQuery);

        List<ExamQuestionVO> examQuestionVOList = BeanCopyUtils.copyBeanList(examQuestionList, ExamQuestionVO.class);

        //查询考题选项
        ExamQuestionItemQuery examQuestionItemQuery = new ExamQuestionItemQuery();
        examQuestionItemQuery.setQuestionIdList(questionIdList);
        List<ExamQuestionItem> examQuestionItemList = examQuestionItemMapper.selectList(examQuestionItemQuery);

        Map<Integer, List<ExamQuestionItem>> tempExamItemMap = examQuestionItemList.stream().collect(Collectors.groupingBy(item -> item.getQuestionId()));

        //查询用户是否已收藏
        AppUserCollectQuery appUserCollectQuery = new AppUserCollectQuery();
        appUserCollectQuery.setObjectIdList(questionIdList);
        appUserCollectQuery.setUserId(appUserCollectQuery.getUserId());
        List<AppUserCollect> appUserCollectList = appUserCollectMapper.selectList(appUserCollectQuery);

        Map<String, AppUserCollect> appUserCollectMap = appUserCollectList.stream().collect(Collectors.toMap(item -> item.getObjectId(),
                Function.identity(), (data1, data2) -> data2));

        for (ExamQuestionVO item : examQuestionVOList) {
            if (appUserCollectMap.get(item.getQuestionId().toString()) != null) {
                item.setHaveCollect(true);
            } else {
                item.setHaveCollect(false);
            }
            item.setExamId(appExamQuestionQuery.getExamId());
            List<ExamQuestionItem> questionItemList = tempExamItemMap.get(item.getQuestionId());
            item.setQuestionItemList(questionItemList);
            if (!appExamQuestionQuery.getShowUserAnswer()) {
                continue;
            }
            AppExamQuestion appExamQuestion = appExamQuestionMap.get(item.getQuestionId());
            if (appExamQuestion != null) {
                item.setAnswerResult(appExamQuestion.getAnswerResult());
                item.setUserAnswer(appExamQuestion.getUserAnswer());
            }
        }
        return examQuestionVOList;
    }

    @Override
    public AppExam postExam(AppUserLoginDto appDto, ExamInfoVo examInfoVo) {
        Date curDate = new Date();
        AppExam appExam = appExamMapper.selectByExamId(examInfoVo.getExamId());
        if (null == appExam || !appExam.getUserId().equals(appDto.getUserId())) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        if (!appExam.getStatus().equals(AppExamStatusEnum.INIT.getStatus())) {
            throw new BusinessException("考试已经提交");
        }

        Map<Integer, ExamItemResult> examResult = examInfoVo.getExamResult();
//        if (examResult.isEmpty()) {
//            throw new BusinessException(ResponseCodeEnum.CODE_600);
//        }

        //查询考试的所有题目
        AppExamQuestionQuery appExamQuestionQuery = new AppExamQuestionQuery();
        appExamQuestionQuery.setExamId(examInfoVo.getExamId());
        List<AppExamQuestion> dbAppExamQuestionList = appExamQuestionMapper.selectList(appExamQuestionQuery);
        List<String> dbQuestionIdList = dbAppExamQuestionList.stream().map(item -> item.getQuestionId().toString()).collect(Collectors.toList());

        //查询问题
        ExamQuestionQuery examQuestionQuery = new ExamQuestionQuery();
        examQuestionQuery.setQueryAnswer(true);
        examQuestionQuery.setQuestionIds(dbQuestionIdList.toArray(new String[examResult.size()]));
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(examQuestionQuery);
        List<AppExamQuestion> appExamQuestionList = new ArrayList<>();
        for (ExamQuestion item : examQuestionList) {
            AppExamQuestion appExamQuestion = new AppExamQuestion();
            if (!examResult.containsKey(item.getQuestionId())) continue;
            ExamItemResult result = examResult.get(item.getQuestionId());
            if (result.getUserAnswer().equals(item.getQuestionAnswer()) || result.getQuestionType() == 3) {
                appExamQuestion.setAnswerResult(AnswerResultEnum.RIGHT.getResult());
                if (result.getQuestionType() == 3) {
                    appExam.setScore(appExam.getScore() + Double.parseDouble(result.getUserAnswer()));
                } else {
                    appExam.setScore(appExam.getScore() + 2.0);
                }
             } else {
                AppExamCount appExamCount = appExamCountMapper.selectOne(new LambdaQueryWrapper<AppExamCount>().
                        eq(AppExamCount::getUId, appExam.getUserId()).
                        eq(AppExamCount::getQId, item.getQuestionId()));
                if (appExamCount != null) {
                    appExamCount.setCount(appExamCount.getCount() + 1);
                    appExamCountMapper.updateById(appExamCount);
                } else {
                    AppExamCount examCount = new AppExamCount();
                    examCount.setQId(item.getQuestionId());
                    examCount.setUId(appExam.getUserId());
                    appExamCountMapper.insert(examCount);
                }
                appExamQuestion.setAnswerResult(AnswerResultEnum.WRONG.getResult());
             }
            appExamQuestion.setId(null);
            appExamQuestion.setUserAnswer(result.getUserAnswer());
            appExamQuestion.setQuestionId(result.getQuestionId());
            appExamQuestion.setExamId(appExam.getExamId());
            appExamQuestion.setUserId(appDto.getUserId());
            appExamQuestionList.add(appExamQuestion);
        }
        if (!appExamQuestionList.isEmpty()) appExamQuestionMapper.insertOrUpdateBatch(appExamQuestionList);
        appExam.setEndTime(curDate);
        appExam.setStatus(AppExamStatusEnum.FINISHED.getStatus());

        AppExam updateAppExam = new AppExam();
        updateAppExam.setStatus(AppExamStatusEnum.FINISHED.getStatus());
        updateAppExam.setEndTime(curDate);
        updateAppExam.setScore(appExam.getScore());

        AppExamQuery appExamQuery = new AppExamQuery();
        appExamQuery.setExamId(appExam.getExamId());
        appExamQuery.setUserId(appExam.getUserId());
        appExamQuery.setStatus(AppExamStatusEnum.INIT.getStatus());
        Integer count = appExamMapper.updateByParam(updateAppExam, appExamQuery);
        if (count == 0) {
            throw new BusinessException("考试提交失败");
        }
        return appExam;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delExam4Api(String userId, Integer examId) {
        appExamMapper.deleteByExamId(examId);
        AppExamQuestionQuery params = new AppExamQuestionQuery();
        params.setExamId(examId);
        params.setUserId(userId);
        appExamQuestionMapper.deleteByParam(params);
    }
}